<?php
namespace app\api\controller;

use app\BaseController;
use app\common\Redis;
use app\model\Demo as SelfModel;
use app\model\DemoRadio;
use app\model\DemoSelect;

use http\Message\Body;
use think\facade\Cache;
use think\facade\Cookie;
use think\Response;
use think\Request;

class Rds extends Base
{


    public function initialize()
    {
        parent::initialize();
        $this->model = "\app\model\Demo";
        $this->list_rows = 10;
        $this->index = ['id','text','textarea','status','radio_id','radio_title','radiotext_id','select_id','select_title','selecttext_id','upload_one','upload_many','file','oss_file','editor','sort','create_time'];
        $this->all = ['id','text','textarea','status','radio_id','radio_title','radiotext_id','select_id','select_title','selecttext_id','upload_one','upload_many','file','oss_file','editor','sort','create_time'];
        $this->my = ['id','text','textarea','status','radio_id','radio_title','radiotext_id','select_id','select_title','selecttext_id','upload_one','upload_many','file','oss_file','editor','sort','create_time'];
        $this->view = ['id','text','textarea','status','radio_id','radio_title','radiotext_id','select_id','select_title','selecttext_id','upload_one','upload_many','file','oss_file','editor','sort','create_time'];
        $this->msg = 'ABCDEF';
        $this->order = ['sort'=>'asc','id'=>'desc'];
        $this->status = [['status','=','1']];
    }

    public function index(Request $request)
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);


        //$redis->set('banlence',100);
       $redis->watch('banlence');

        $redis->multi();

        $redis->decr('banlence');

//        if($tr < 0){
//            return ['code'=>400,'msg'=>'失败'];
//        }
//        if($get >= 1){
//
//        }else{
//
//        }

//        $rds = \app\model\Rds::where('id',1)->value('number');
//        if($rds <= 0){
//         //   return ['code'=>400,'msg'=>'失败'];
//        }
       // \app\model\Rds::where('id',1)->dec('number')->update();

        $ret = $redis->get('banlence');

//       $exec = $redis->exec();
//        var_export($exec);die;
//        if($exec[0] <=0){
//
//            $redis->discard();
//        }
    }

    public function set(Request $request)
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
        $rds = \app\model\Rds::where('id',1)->value('number');
        Cache::set('n',50);
       return $redis->set('banlence',50);

    }
    public function get(Request $request)
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
        $rds = \app\model\Rds::where('id',1)->value('number');
//        return Cache::get('n');
        return $redis->get('banlence');

    }

    public function test34()
    {
        $redis = Redis::init();
        $redis->set('stock', 10000);
        $redis->del('queue');
        //以上两行代码，为不加锁代码，并发情况下，抢到相同库存号；
        $redis->set('stock_transaction', 50);
        $redis->del('queue_transaction');
        $redis->del('exec');
        $redis->set('count',0);//判定大于零次数
        $redis->set('buyer',0);//买家个数
        $redis->del('lock:stock');//释放锁
        Cache::set('cn',0);
        echo '初始化Redis扣库存测试数据<br/>';
        echo 'test35无事务，无锁<br/>';
        echo 'test36有事务，无锁<br/>';
        echo 'test37有事务，watch乐观锁<br/>';
        echo 'test38有事务，setnx分布式锁<br/>';
    }
    //抢库存  无锁   并发情况下，抢到相同库存号；
    public function test35()
    {
        $redis = Redis::init();

        $stock = $redis->get('stock');
        $redis->decr('stock');
        $redis->lpush('queue', $stock);
        \app\model\Rds::create(['number'=>$stock]);
        echo "抢到第 $stock 个";
    }

    //抢库存，事务，无锁,超卖了
    /**
     * 注意，Redis事务中，不能和PHP进行交互 但是可以exec后，会返回事务中各条命令的值
     *
     * 命令错误        事务全部命令不执行
     * 命令操作对象错误   事务全部命令执行
     */
    public function test36()
    {
        $redis = Redis::init();
        $redis->incr('buyer');//买家个数

        $buy=1;//循环标志
        do {
            if ($redis->get('stock_transaction')>0){
                $redis->incr('count');//判定大于零次数
                usleep(rand(0,100000));//给时间给别人改
                $a = $redis->get('stock_transaction');
                $redis->multi();
                \app\model\Rds::create(['number'=>$a]);
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值
                $redis->lpush('queue_transaction',1);//用于统计执行次数,实际业务可以用于存放Uid    返回内部元素个数
                $ok=$redis->exec();//返回事务内，所有命令的返回值，按命令先后排序，当操作别打断时，返回空
                if (is_array($ok)){

                    $redis->lpush('exec',json_encode($ok));
                    echo '买到了第'.($ok[0]+1).'个';
                    $buy=0;
                }else{
                    usleep(rand(0,100000));
                }
                //这里要解决被别人改掉以后，重试问题
            }else{
                echo '已经销售一空了';
                $buy=0;
            }
        }while($buy);
    }

    //watch锁加事务 不会超卖   乐观锁，适用于读多写少的情况    得到的响应数据，比较凌乱
    public function test37(Request $request)
    {
        $redis = Redis::init();
//        $buyer = $redis->incr($request->ip());//买家个数
//        $redis->expire($request->ip(), 1);
//        $cache = Cache::get($request->ip());
//        Cache::set($request->ip(),'abadf',1);
//        $buy = 1;//循环标志
//        if ($cache) {
//            return ['code' => 400, 'msg' => '提交过于频繁'.$cache];
//        }
        do {
            $redis->watch('stock_transaction');
            if ($redis->get('stock_transaction') > 0) {

                sleep(1);
                $redis->incr('count');//判定大于零次数
                usleep(rand(0, 100000));//给时间给别人改
                $a = $redis->get('stock_transaction');
                $redis->multi();
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值
                $redis->lpush('queue_transaction', 1);//用于统计执行次数,实际业务可以用于存放Uid    返回内部元素个数
                $ok = $redis->exec();//返回事务内，所有命令的返回值，按命令先后排序，当操作别打断时，返回空
                // $cn = Cache::inc('cn');
                if (is_array($ok)) {

                    \app\model\Rds::create(['number' => $a]);
                    $redis->lpush('exec', json_encode($ok));
                    return ['code' => 400, 'msg' => '成功'];
                    echo '买到了第' . ($ok[0] + 1) . '个';
                    $buy = 0;
                } else {
                    usleep(rand(0, 100000));
                }
                //这里要解决被别人改掉以后，重试问题
            } else {
                echo '已经销售一空了';
                $buy = 0;
            }
        } while ($buy);
    }
    //redis 悲观锁模拟抢购，适用于写多，读少的情况   悲观锁，得到的响应数据，很整齐划一
    public function test38(){
        $redis = Redis::init();
        $redis->incr('buyer');//买家个数
        $buy=1;//循环标志
        do {
            if ($this->redisLock() and $redis->get('stock_transaction')>0){//注意，这里的获取锁，需要放到前面，否则超卖
                $redis->incr('count');//判定大于零次数
                usleep(rand(0,100000));//给时间给别人改
                $a = $redis->get('stock_transaction');
                $redis->multi();
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值
                $redis->lpush('queue_transaction',1);//用于统计执行次数,实际业务可以用于存放Uid    返回内部元素个数
                $ok=$redis->exec();//返回事务内，所有命令的返回值，按命令先后排序，当操作别打断时，返回空
                if (is_array($ok)){
                    \app\model\Rds::create(['number'=>$a]);
                    $redis->lpush('exec',json_encode($ok));
                    echo '买到了第'.($ok[0]+1).'个';
                    $buy=0;
                }else{
                    usleep(rand(0,100000));
                }
                //这里要解决被别人改掉以后，重试问题
            }else{
                echo '已经销售一空了';
                $buy=0;
            }
            $this->redisUnlock();
        }while($buy);
    }
    //redis 库存实验获得锁
    public function redisLock(){
        $redis = Redis::init();
        do{
            $lock=$redis->setnx('lock:stock',1);//不存在，执行操作，返回1，即上锁   ，存在则不操作，返回0；
            if ($lock){
                $redis->expire('lock:stock',60);//60s过期  防止死锁
                return true;
            }else{
                usleep(rand(0,100000));
            }
        }while(1);
    }
    //redis 库存实验解除锁
    public function redisUnlock()
    {
        $redis = Redis::init();
        $redis->del('lock:stock');
    }

    public function lpush()
    {
        $redis = Redis::init();

        $redis->incr('lpush');
        $lpush = $redis->get('lpush');
        $result = $redis->lpush('order', $lpush);
    }

    public function lrange()
    {
        $redis = Redis::init();
        $ret = $redis->lRange('order',0,-1);
        return ($ret);
    }

    public function brpop()
    {
        $redis = Redis::init();
        $result = $redis->brpop('order',0);
        var_export($result);die;
    }

    public function rpop()
    {
        $redis = Redis::init();
        $result = $redis->rpop('order');
        if($result){
            \app\model\Rds::create(['number'=>$result]);
        }

        var_export($result);die;
    }

    public function init(){
        $redis = Redis::init();
        $redis->flushAll();
    }

    public function incr(Request $request)
    {

        $redis = Redis::init();

        $buy = 1;//循环标志
        do {
            if ($this->redisLock() && $redis->get('stock_transaction') > 0) {

                usleep(rand(0, 100000));//给时间给别人改
                $a = $redis->get('stock_transaction');
                $redis->multi();
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值

                $ok = $redis->exec();//返回事务内，所有命令的返回值，按命令先后排序，当操作别打断时，返回空
                if (is_array($ok)) {
                    \app\model\Rds::create(['number' => $a]);

                    echo '买到了第' . ($ok[0] + 1) . '个';
                    $buy = 0;
                }else{
                    usleep(rand(0,100000));
                }

            }else{
                $buy=0;
            }
            $this->redisUnlock();
        } while ($buy);

    }

    public function test39()
    {
        $redis = Redis::init();



            $a = $redis->get('stock_transaction');
            $ret = $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值


                if ($ret >= 0) {
                    \app\model\Rds::create(['number' => $a]);
                }



    }

    public function test381(){
        $redis = Redis::init();
        $redis->incr('buyer');//买家个数
        $buy=1;//循环标志
        do {
            if ($this->redisLock() && $redis->get('stock_transaction')>0){//注意，这里的获取锁，需要放到前面，否则超卖
                $redis->incr('count');//判定大于零次数
                usleep(rand(0,100000));//给时间给别人改
                $a = $redis->get('stock_transaction');
                $redis->multi();
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值
                $redis->lpush('queue_transaction',1);//用于统计执行次数,实际业务可以用于存放Uid    返回内部元素个数
                $ok=$redis->exec();//返回事务内，所有命令的返回值，按命令先后排序，当操作别打断时，返回空
                if (is_array($ok)){
                    \app\model\Rds::create(['number'=>$a]);
                    $redis->lpush('exec',json_encode($ok));
                    echo '买到了第'.($ok[0]+1).'个';
                    $buy=0;
                }else{
                    usleep(rand(0,100000));
                }
                //这里要解决被别人改掉以后，重试问题
            }else{
                echo '已经销售一空了';
                $buy=0;
            }
            $this->redisUnlock();
        }while($buy);
    }

    public function file_lock()
    {
        $redis = Redis::init();
        $fp = fopen("file_lock.txt", "r");
        if (flock($fp, LOCK_EX)) {
            if ($redis->get('stock_transaction')>0){
                sleep(1);
                $a = $redis->get('stock_transaction');
                $redis->decr('stock_transaction');//扣库存        //返回扣库存后的值
                \app\model\Rds::create(['number' => $a]);
            }
        }
        fclose($fp);
    }

    public function ajax()
    {
        return view();
    }



}
